An explosion of both data and operations is required to rasterize a polygon as individual pixels. Typically, the operations include depth comparison, Gouraud shading, color blending, logical operations, texture mapping, and possibly antialiasing. The following techniques can improve performance for a fill-limited application:
To reduce fill-limited drawing, use backface or frontface removal. For example, if you are drawing a sphere, half of its polygons are backfacing at any given time. Backface and frontface removal is done after transformation calculations but before per-fragment operations. This means that backface removal may make transform-limited polygons somewhat slower, but make fill-limited polygons significantly faster. You can turn on backface removal when you are drawing an object with many backfacing polygons, then turn it off again when drawing is completed.
Any rendering operation can become fill-limited for large polygons. Clever structuring of drawing can eliminate the need for certain fill operations. For example, if large backgrounds are drawn first, they do not need to be depth buffered. It is better to disable depth buffering for the backgrounds and then enable it for other objects where it is needed.
Games and flight simulators often use this technique. The sky and ground are drawn with depth buffering disabled, then the polygons lying flat on the ground (runway and grid) are drawn without a performance penalty. Finally, depth buffering is enabled for drawing the mountains and airplanes.
There are many other special cases in which depth buffering might not be required. For example, terrain, ocean waves, and 3D function plots are often represented as height fields (X-Y grids with one height value at each lattice point). It's straightforward to draw height fields in back-to-front order by determining which edge of the field is furthest away from the viewer, then drawing strips of triangles or quadrilaterals parallel to that starting edge and working forward. The entire height field can be drawn without depth testing, provided it doesn't intersect any piece of previously-drawn geometry. Depth values need not be written at all, unless subsequently-drawn depth buffered geometry might intersect the height field; in that case, depth values for the height field should be written, but the depth test can be avoided by calling
glDepthFunc(GL_ALWAYS)
Alpha blending is an expensive operation. A common use of alpha blending is for transparency, where the alpha value denotes the opacity of the object. For fully opaque objects, disable alpha blending.
Turn off per-fragment operations for objects that do not require them, and structure the drawing process to minimize their use without causing excessive toggling of modes.
For example, setting the GL_PERSPECTIVE_CORRECTION_HINT to GL_FASTEST and the texture environment to GL_REPLACE often improves performance significantly. Also, avoid expensive filtering modes such as bilinear and trilinear filtering, if possible.
For example, if a scene has large background polygons, draw them first without depth buffering, then render the more complex depth-buffered objects.
The optimum size of polygons depends on the other operations going on in the pipeline:
Use the simplest possible fill algorithms for drawing very large polygons, such as backgrounds.
The most basic per-frame operations are clearing the color and depth buffers. On some systems, there are optimizations for common special cases of these operations.
Whenever you need to clear both the color and depth buffers, don't clear each buffer independently. Instead use
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
Disable dithering before clearing.